# 请求日志中间件

import time
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from typing import Callable
import json
from src.utils.logger import app_logger as logger


class RequestLoggingMiddleware(BaseHTTPMiddleware):
    """请求日志中间件"""
    
    def __init__(self, app, log_level: str = "INFO"):
        super().__init__(app)
        self.log_level = log_level.upper()
    
    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        # 记录请求开始时间
        start_time = time.time()
        
        # 获取请求信息
        method = request.method
        url = str(request.url)
        client_ip = self._get_client_ip(request)
        user_agent = request.headers.get("user-agent", "")
        
        # 记录请求体（仅对POST/PUT/PATCH请求）
        request_body = None
        if method in ["POST", "PUT", "PATCH"]:
            try:
                body = await request.body()
                if body:
                    # 尝试解析JSON，如果失败则记录原始字符串
                    try:
                        request_body = json.loads(body.decode())
                    except (json.JSONDecodeError, UnicodeDecodeError):
                        request_body = body.decode("utf-8", errors="ignore")[:500]  # 限制长度
            except Exception:
                request_body = "<无法读取请求体>"
        
        # 记录请求日志
        logger.info(
            f"Request started - {method} {url} from {client_ip} | "
            f"User-Agent: {user_agent[:100]}{'...' if len(user_agent) > 100 else ''}"
        )
        
        if request_body and self.log_level == "DEBUG":
            logger.debug(f"Request body: {request_body}")
        
        # 处理请求
        try:
            response = await call_next(request)
        except Exception as e:
            # 记录异常
            process_time = time.time() - start_time
            logger.error(
                f"Request failed - {method} {url} from {client_ip} | "
                f"Error: {str(e)} | Duration: {process_time:.3f}s"
            )
            raise
        
        # 计算处理时间
        process_time = time.time() - start_time
        
        # 记录响应日志
        logger.info(
            f"Request completed - {method} {url} from {client_ip} | "
            f"Status: {response.status_code} | Duration: {process_time:.3f}s"
        )
        
        # 添加响应头
        response.headers["X-Process-Time"] = str(process_time)
        
        return response
    
    def _get_client_ip(self, request: Request) -> str:
        """获取客户端真实IP地址"""
        # 优先从代理头中获取真实IP
        forwarded_for = request.headers.get("X-Forwarded-For")
        if forwarded_for:
            return forwarded_for.split(",")[0].strip()
        
        real_ip = request.headers.get("X-Real-IP")
        if real_ip:
            return real_ip
        
        # 如果没有代理头，则使用客户端IP
        if request.client:
            return request.client.host
        
        return "unknown"